
import json
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.enum.text import PP_PARAGRAPH_ALIGNMENT
import threading
import textwrap

class SmartPptConverter:
    def __init__(self, json_data, output_path, update_ui):
        self.json_data = json_data
        self.output_path = output_path
        self.update_ui = update_ui
        self.max_width = 60  # 每行最大字符数
        self.canceled = False

    def wrap_text(self, text):
        """智能文本换行处理"""
        return '\n'.join(textwrap.wrap(text, width=self.max_width))

    def create_slide(self, prs, title, content):
        """创建单张幻灯片并处理自动换行"""
        slide = prs.slides.add_slide(prs.slide_layouts[1])
        slide.shapes.title.text = title
        
        textbox = slide.shapes.add_textbox(
            Inches(1), Inches(1.5), Inches(8), Inches(4.5)
        )
        tf = textbox.text_frame
        tf.word_wrap = True
        
        # 设置自动换行和字体
        p = tf.add_paragraph()
        p.text = self.wrap_text(content)
        p.font.size = Pt(14)
        p.alignment = PP_PARAGRAPH_ALIGNMENT.LEFT

    def convert(self):
        try:
            prs = Presentation()
            total = len(self.json_data)
            
            for i, item in enumerate(self.json_data):
                if self.canceled:
                    return False
                
                title = item.get("title", f"幻灯片 {i+1}")
                content = item.get("content", "")
                self.create_slide(prs, title, content)
                
                progress = int((i+1)/total*100)
                self.update_ui(progress, f"处理中: {i+1}/{total}")
            
            if not self.canceled:
                prs.save(self.output_path)
                return True
            return False
            
        except Exception as e:
            raise e

class ConverterApp:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("智能PPT生成器")
        self.setup_ui()
        self.converter = None

    def setup_ui(self):
        # 文件选择区域
        frame = tk.Frame(self.root, padx=10, pady=10)
        frame.pack(fill=tk.X)
        
        tk.Label(frame, text="JSON文件:").grid(row=0, column=0, sticky='w')
        self.json_entry = tk.Entry(frame, width=40)
        self.json_entry.grid(row=0, column=1, padx=5)
        tk.Button(frame, text="浏览", command=self.browse_json).grid(row=0, column=2)
        
        tk.Label(frame, text="PPT输出:").grid(row=1, column=0, sticky='w')
        self.ppt_entry = tk.Entry(frame, width=40)
        self.ppt_entry.grid(row=1, column=1, padx=5)
        tk.Button(frame, text="浏览", command=self.browse_ppt).grid(row=1, column=2)
        
        # 进度显示
        self.progress = ttk.Progressbar(self.root, orient='horizontal', length=400)
        self.progress.pack(pady=10)
        self.status = tk.Label(self.root, text="准备就绪")
        self.status.pack()
        
        # 操作按钮
        btn_frame = tk.Frame(self.root)
        btn_frame.pack(pady=10)
        tk.Button(btn_frame, text="开始转换", command=self.start).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="取消", command=self.cancel).pack(side=tk.LEFT)

    def browse_json(self):
        path = filedialog.askopenfilename(filetypes=[("JSON文件", "*.json")])
        if path:
            self.json_entry.delete(0, tk.END)
            self.json_entry.insert(0, path)

    def browse_ppt(self):
        path = filedialog.asksaveasfilename(
            defaultextension=".pptx",
            filetypes=[("PPT文件", "*.pptx")]
        )
        if path:
            self.ppt_entry.delete(0, tk.END)
            self.ppt_entry.insert(0, path)

    def update_ui(self, value, message):
        self.progress['value'] = value
        self.status.config(text=message)
        self.root.update()

    def start(self):
        json_path = self.json_entry.get()
        ppt_path = self.ppt_entry.get()
        
        if not json_path or not ppt_path:
            messagebox.showerror("错误", "请选择输入和输出文件")
            return
            
        try:
            with open(json_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
                
            self.converter = SmartPptConverter(
                data, ppt_path, self.update_ui
            )
            threading.Thread(target=self.run_conversion, daemon=True).start()
            
        except Exception as e:
            messagebox.showerror("错误", f"加载文件失败: {str(e)}")

    def run_conversion(self):
        try:
            if self.converter.convert():
                messagebox.showinfo("成功", "PPT生成完成！")
            self.update_ui(0, "准备就绪")
        except Exception as e:
            messagebox.showerror("错误", f"转换失败: {str(e)}")

    def cancel(self):
        if hasattr(self, 'converter') and self.converter:
            self.converter.canceled = True
            self.update_ui(0, "已取消")

    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    app = ConverterApp()
    app.run()
